﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Configuration;

namespace WorkTool
{
	public partial class NoteTaker : UserControl
	{
		public NoteTaker()
		{
			InitializeComponent();
		}
		public NoteTaker(string RootFolder)
		{
			InitializeComponent();
			RootDirectory = RootFolder;
		}
		public string
			RootDirectory = "",
			FileMask = "",
			OriginalText = "",
			OpenFile = "";

		public event EventHandler Save;

		private void NoteTaker_Load(object sender, EventArgs e)
		{
			FileMask = ConfigurationManager.AppSettings["FileMask"] ?? "*";
			RootDirectory = ConfigurationManager.AppSettings["NotesRootDirectory"] ??  @"c:\notes\";
			if (!RootDirectory.EndsWith(@"\")) RootDirectory += @"\";

			if (string.IsNullOrEmpty(RootDirectory)) throw new ApplicationException("Root Folder is null; I don't know where to look!");
			if (!System.IO.Directory.Exists(RootDirectory))
			{
				DialogResult dr = MessageBox.Show("Root folder does not exist, create?\n" + RootDirectory, "User intervention required", MessageBoxButtons.YesNo);
				if (dr == DialogResult.Yes) System.IO.File.Create(RootDirectory);
				else return;
			}
			PopulateTreeView();
			treeView1.SelectedNode = treeView1.Nodes[0];
		}
		private void btnAddFolder_Click(object sender, EventArgs e)
		{
			// Make sure we have a node selected
			if (treeView1.SelectedNode == null && treeView1.Nodes.Count > 0) 
				treeView1.SelectedNode = treeView1.Nodes[0];
			else if (treeView1.SelectedNode == null)
				throw new ApplicationException("Unable to add a new directory because the root directory is not set.");

			// Find out what directory the user wants to create
			GetString gs = new GetString("Enter the name of the directory to create: ");
			gs.ShowDialog();
			DialogResult dr = gs.DialogResult;
			if (gs.DialogResult == DialogResult.Cancel) return;

			// Attempt to create directory
			Dir dir = (Dir)treeView1.SelectedNode.Tag;
			try
			{
				System.IO.Directory.CreateDirectory(dir.Name + "\\" + gs.TextValue);
				PopulateTreeView();
			}
			catch (Exception ex) 
			{
				System.Windows.Forms.MessageBox.Show("An error occurred creating the folder: \n" + ex.Message);
				return;
			}

			// Find and focus the node
			treeView1.Select();
			TreeNode createdNode = GetNodeMatchingName(treeView1.Nodes[0], gs.TextValue);
			if (createdNode != null) treeView1.SelectedNode = createdNode;
			else MessageBox.Show("Error: Unable to find the node of the directory I just created.");
		}
		private void btnRemDir_Click(object sender, EventArgs e)
		{
			// Make sure we have a node selected
			if (treeView1.SelectedNode == null && treeView1.Nodes.Count > 0)
				treeView1.SelectedNode = treeView1.Nodes[0];
			else if (treeView1.SelectedNode == null)
				throw new ApplicationException("Unable to delete a directory because there are no directories to delete.");

			if (treeView1.SelectedNode == treeView1.Nodes[0])
			{
				MessageBox.Show("User is disallowed from deleting the root node.");
				return;
			}

			if (MessageBox.Show("Really delete " + ((Dir)treeView1.SelectedNode.Tag).Name + " and all child objects?", "User intervention required", MessageBoxButtons.YesNo) != DialogResult.Yes)
				return;

			int NumObjects = System.IO.Directory.GetFiles(((Dir)treeView1.SelectedNode.Tag).Name, "*", System.IO.SearchOption.AllDirectories).Length;
			NumObjects += System.IO.Directory.GetDirectories(((Dir)treeView1.SelectedNode.Tag).Name, "*", System.IO.SearchOption.AllDirectories).Length;
			if (NumObjects > 0 && MessageBox.Show("This directory contains "+NumObjects.ToString()+" child objects. Really continue?","Check yourself",MessageBoxButtons.YesNo) != DialogResult.Yes)
				return;

			try
			{
				System.IO.Directory.Delete(((Dir)treeView1.SelectedNode.Tag).Name, true);
				
			}
			catch (Exception ex)
			{
				MessageBox.Show("The following error occurred deleting " + ((Dir)treeView1.SelectedNode.Tag).Name + ":\n" + ex.Message);
			}
			PopulateTreeView();
			treeView1.Select();
		}
		private void btnRemFile_Click(object sender, EventArgs e)
		{

			if (listBox1.SelectedItems.Count == 1 && MessageBox.Show("Really delete this file?\n" + OpenFile, "User Intervention Required", MessageBoxButtons.YesNo) == DialogResult.No)
				return;
			else if (listBox1.SelectedItems.Count > 1 && MessageBox.Show("Really delete these " + listBox1.SelectedItems.Count.ToString() + " files?", "User Intervention Required", MessageBoxButtons.YesNo) == DialogResult.No)
				return;

			foreach (string file in listBox1.SelectedItems)
			{
				string filename = ((Dir)treeView1.SelectedNode.Tag).Name + "\\" + file;
				if (!System.IO.File.Exists(filename))
				{
					MessageBox.Show("Cannot delete " + filename + ": The file no longer exists.");
					return;
				}

				try
				{
					System.IO.File.Delete(filename);
				}
				catch (Exception ex)
				{
					MessageBox.Show("An error ocurred deleting the file " + filename + ":\n" + ex.Message);
				}
			}
			PopulateFiles();
		}
		private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
		{
			SaveFile();
			OpenFile = "";
			OriginalText = "";
			textBox1.Text = "";

			if (treeView1.SelectedNode == null)
			{
				btnAddFile.Enabled = false;
				btnAddFolder.Enabled = false;
				btnRemDir.Enabled = false;
				btnRemFile.Enabled = false;
			}
			else
			{
				btnAddFile.Enabled = true;
				btnAddFolder.Enabled = true;
				btnRemDir.Enabled = true;
				btnRemFile.Enabled = true;
			}

			PopulateFiles();
			textBox1.Visible = false;
		}
		private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
		{
			// Save & Reset
			SaveFile();
			OpenFile = "";
			OriginalText = "";
			textBox1.Text = "";
			if (listBox1.SelectedItem == null)
			{
				textBox1.Visible = false;
				return;
			}

			// Check target file
			string filename = ((Dir)treeView1.SelectedNode.Tag).Name + "\\" + (string)listBox1.SelectedItem;
			if (!System.IO.File.Exists(filename))
			{
				MessageBox.Show("Cannot load file; it no longer exists:\n" + filename);
				return;
			}
			string ext = "";
			if (filename.Contains("."))
				ext = filename.Substring(filename.LastIndexOf('.')+1);

			// Attempt to load target file
			switch (ext.ToLower().Trim())
			{
				case "png":
				case "jpg":
				case "gif":
				case "bmp":
					try
					{
						pictureBox1.Image = Image.FromFile(filename);
						textBox1.Visible = false;
						pictureBox1.Visible = true;
						OpenFile = null;
						OriginalText = null;
					}
					catch (Exception ex)
					{
						MessageBox.Show("An error occurred attempting to read image: " + filename + "\n" + ex.Message);
					}
					break;
				case "txt":
				case "nfo":
				case "diz":
				case "xml":
				case "xsl":
				case "":
				default:
					try
					{
						textBox1.Text = System.IO.File.ReadAllText(filename);
						OriginalText = textBox1.Text;
						OpenFile = filename;
						pictureBox1.Visible = false;
						textBox1.Visible = true;
						textBox1.Focus();
						textBox1.SelectionLength = 0;
						textBox1.SelectionStart = textBox1.Text.Length;
						textBox1.ScrollToCaret();
					}
					catch (Exception ex)
					{
						MessageBox.Show("An error occurred attempting to read text file: " + filename + "\n" + ex.Message);
					}
					break;
			}
		}
		private void pictureBox1_DoubleClick(object sender, EventArgs e)
		{
			if (listBox1.SelectedItem == null)
				return;
			string filename = ((Dir)treeView1.SelectedNode.Tag).Name + "\\" + (string)listBox1.SelectedItem;
			System.Diagnostics.Process.Start(filename);
		}
		private void btnAddFile_Click(object sender, EventArgs e)
		{
			// Save existing file and reset
			SaveFile();
			OpenFile = "";
			OriginalText = "";
			textBox1.Text = "";

			// Make sure we have a node selected
			if (treeView1.SelectedNode == null && treeView1.Nodes.Count > 0)
				treeView1.SelectedNode = treeView1.Nodes[0];
			else if (treeView1.SelectedNode == null)
				throw new ApplicationException("Unable to add a new directory because the root directory is not set.");

			GetString gs = new GetString("Enter the filename to create:");
			gs.ShowDialog();
			if (gs.DialogResult != DialogResult.OK) return;
			string filename = gs.TextValue;
			if (string.IsNullOrEmpty(gs.TextValue))
			{
				MessageBox.Show("Filename empty, try again.");
				return;
			}
			filename = filename.Trim();

			if (!filename.ToLower().EndsWith(".txt") && MessageBox.Show("Append \".txt\"?", "User Intervention Required", MessageBoxButtons.YesNo) == DialogResult.Yes)
				filename += ".txt";

			if (!new System.Text.RegularExpressions.Regex(@"[a-zA-Z0-9_ ]").IsMatch(filename))
			{
				MessageBox.Show("Filename doesn't match regex @\"[a-zA-Z0-9_ ]\"; try again.");
				return;
			}

			try
			{
				System.IO.File.Create(((Dir)treeView1.SelectedNode.Tag).Name + "\\" + filename);
				string file = ((Dir)treeView1.SelectedNode.Tag).Name + "\\" + filename;
				PopulateFiles();
				OpenFile = file;
				OriginalText = "";
				listBox1.Focus();

				foreach (object o in listBox1.Items)
					if ((string)o == OpenFile)
					{
						listBox1.SelectedItem = o;
						break;
					}


				pictureBox1.Visible = false;
				textBox1.Visible = true;
				textBox1.Focus();

				SaveFile();
			}
			catch (Exception ex)
			{
				OpenFile = null;
				MessageBox.Show("An error occurred creating file " + ((Dir)treeView1.SelectedNode.Tag).Name + "\\" + filename + ":\n" + ex.Message);
			}
		}
		private void timer1_Tick(object sender, EventArgs e)
		{
			SaveFile();
		}
		private void textBox1_Leave(object sender, EventArgs e)
		{
			SaveFile();
		}

		/// <summary>Populates the tree view.</summary>
		/// 
		public void PopulateTreeView()
		{
			treeView1.Nodes.Clear();
			treeView1.Nodes.Add(new Dir(RootDirectory, FileMask).GetTreeNode());
			treeView1.ExpandAll();
		}
		public void PopulateFiles()
		{
			SaveFile();
			OpenFile = "";
			OriginalText = "";
			textBox1.Text = "";
			listBox1.Items.Clear();
			foreach (File f in ((Dir)treeView1.SelectedNode.Tag).GetFiles())
				listBox1.Items.Add(f.GetFriendlyName());
		}
		private void SaveFile()
		{
			if (!string.IsNullOrEmpty(OpenFile) && textBox1.Text != OriginalText)
			{
				try
				{
					System.IO.File.WriteAllText(OpenFile, textBox1.Text);
					Save(timer1, EventArgs.Empty);
					OriginalText = textBox1.Text;
					Save(textBox1, EventArgs.Empty);
				}
				catch (Exception ex)
				{
					MessageBox.Show("An error occurred saving file " + OpenFile + ":\n" + ex.Message);
				}
			}
		}
		public void DoSaveFile()
		{
			if (!string.IsNullOrEmpty(OpenFile))
				SaveFile();
		}

		private TreeNode GetNodeMatchingName(TreeNode Parent, string SearchString)
		{
			if (Parent.Name == SearchString) return Parent;

			TreeNode target = null;
			foreach (TreeNode node in Parent.Nodes)
			{
				if (node.Name == SearchString) return node;
				target = GetNodeMatchingName(node, SearchString);
				if (target != null) return target;
			}
			return null;
		}

		~NoteTaker () {
			SaveFile();
		}
	}

	public class Dir
	{
		public Dir(string directory, string filemask)
		{
			if (!System.IO.Directory.Exists(directory)) throw new ApplicationException("Directory does not exist: \n" + directory);
			Name = directory.Trim();
			if (Name.EndsWith("\\"))
				Name = Name.Substring(0, Name.Length - 1);
			Filemask = filemask;
			dirs = GetDirs();
			files = GetFiles();
		}

		public List<Dir> dirs;
		public List<File> files;
		public string Name = "";
		public string Filemask = "";

		public List<Dir> GetDirs()
		{
			dirs = new List<Dir>();
			foreach (string dir in System.IO.Directory.GetDirectories(Name))
				dirs.Add(new Dir(dir, Filemask));
			return dirs;
		}
		public List<File> GetFiles()
		{
			files = new List<File>();
			foreach (string file in System.IO.Directory.GetFiles(Name, Filemask ?? "*"))
				files.Add(new File(file));
			return files;
		}
		public string GetFriendlyName()
		{
			if (!Name.Contains("\\")) return Name;
			string name = Name;
			if (name.Trim().EndsWith("\\")) name = name.Substring(0,name.Length - 1);
			return name.Substring(name.LastIndexOf("\\") + 1);
		}
		public TreeNode GetTreeNode()
		{
			TreeNode tn = new TreeNode(GetFriendlyName());
			tn.Tag = this;
			tn.ToolTipText = Name;
			tn.Name = GetFriendlyName();

			foreach (Dir dir in GetDirs())
				tn.Nodes.Add(dir.GetTreeNode());


			return tn;
		}
		

	}
	public class File
	{
		public File(string name)
		{
			Name = name;
		}

		public string Name = "";
		public string Open()
		{
			if (!System.IO.File.Exists(Name)) throw new ApplicationException("File does not exist: \n" + Name);
			return System.IO.File.ReadAllText(Name);
		}
		public string GetFriendlyName()
		{
			if (!Name.Contains("\\")) return Name;
			return Name.Substring(Name.LastIndexOf("\\") + 1);
		}
	}
	public delegate void StringEventHandler(string message);

}
